<?php

namespace JLPay\Models;

use JLPay\Core\OrgConfig;
use JLPay\Exceptions\ConfigException;

/**
 * 基础请求类
 */
abstract class BaseRequest
{
    /**
     * 转换为数组
     *
     * @return array
     */
    public function toArray(): array
    {
        $reflection = new \ReflectionClass($this);
        $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_PRIVATE);

        $result = [];
        foreach ($properties as $property) {
            $property->setAccessible(true);
            $value = $property->getValue($this);
            if ($value !== null) {
                // 将驼峰命名转换为下划线命名
                $key = $this->camelToSnake($property->getName());
                $result[$key] = $this->convertValue($value);
            }
        }

        return $result;
    }

    /**
     * 转换值
     *
     * @param mixed $value
     * @return mixed
     */
    private function convertValue($value)
    {
        if (is_object($value) && method_exists($value, 'toArray')) {
            return $value->toArray();
        } elseif (is_array($value)) {
            // 空数组转换为空对象，避免JSON序列化为[]而不是{}
            if (empty($value)) {
                return new \stdClass();
            }
            $result = [];
            foreach ($value as $k => $v) {
                $result[$k] = $this->convertValue($v);
            }
            return $result;
        }
        return $value;
    }

    /**
     * 将驼峰命名转换为下划线命名
     *
     * @param string $camelCase
     * @return string
     */
    private function camelToSnake(string $camelCase): string
    {
        return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $camelCase));
    }

    /**
     * 校验必填参数
     *
     * @param OrgConfig $config
     * @throws ConfigException
     */
    public function checkRequiredParams(OrgConfig $config): void
    {
        // 子类可以重写此方法来实现特定的参数校验
    }

    /**
     * 检查是否需要加密
     *
     * @return bool
     */
    public function requiresEncrypt(): bool
    {
        return false; // 默认不需要加密
    }

    /**
     * 获取敏感字段列表
     *
     * @return array
     */
    public function getSensitiveFields(): array
    {
        return []; // 默认没有敏感字段
    }
} 